﻿/**
 * @file service_proxy_mgr.hpp
 * @date 2021/06/15 14:06
 * 
 * @author harrybao (harrybao@123u.com)
 * 
 * @brief 公会客户端代理管理
 * 
 * @version v1.0.0
 * 
 * @copyright Copyright © 2021 All Rights Reserved 上海欢乐互娱网络科技有限公司
 * 
 * @par history:
 * <table>
 * <tr><th>Date                     <th>Version     <th>Author      <th>Description
 * <tr><td>2021/06/15 14:06         <td>1.0.0       <td>harrybao    <td>创建初始版本
 * </table>
 */

#pragma once

#include <unordered_map>
#include <memory>
#include "rpc_root.h"
#include "context/service_context.hpp"

namespace guild_service {
namespace common {

/**
 * @brief 公会客户端连接管理类
 *
 */
template <typename ClientProxy>
class ServiceProxyMgr final {
 public:
  ServiceProxyMgr() = default;
  ~ServiceProxyMgr() = default;

  // ServiceProxyMgr(const GuildServiceProxyMgr<ClientProxy> &) = delete;
  // ServiceProxyMgr(GuildServiceProxyMgr<ClientProxy> &&) = delete;
  // const ServiceProxyMgr<ClientProxy> &operator=(
  //     const ServiceProxyMgr<ClientProxy> &) = delete;
  // const ServiceProxyMgr<ClientProxy> &operator=(
  //     ServiceProxyMgr<ClientProxy> &&) = delete;

 public:

  /**
   * @brief 注册
   *
   * @param call 注册请求
   * @param role_uuid 角色唯一id
   * @return 注册结果
   */
  bool Login(rpc::StubCallPtr call, const role_uuid_type role_uuid) {
    if (!call) {
      // for unittest
      return true;
    }
    auto proxy_ptr = ServiceContextSingleton()->get_proxy_from_peer<ClientProxy>(call);
    if (!proxy_ptr) {
      return false;
    }
    if (!proxy_ptr->isConnected()) {
      return false;
    }

    return client_proxy_map_.emplace(role_uuid, proxy_ptr).second;
  }

  /**
   * @brief 未注册
   * 
   * @param role_uuid 角色唯一id
   * @return 未注册结果
   */
  bool Logout(const role_uuid_type role_uuid) {
    return client_proxy_map_.erase(role_uuid) > 0;
  }

  /**
   * @brief 获取客户端代理
   * 
   * @param role_uuid 角色唯一id
   * @return std::shared_ptr<ClientProxy> 
   */
  std::shared_ptr<ClientProxy> GetProxy(const role_uuid_type role_uuid) const {
    auto it = client_proxy_map_.find(role_uuid);
    if (it == client_proxy_map_.end()
      || it->second->isConnected()) {
      return std::shared_ptr<ClientProxy>(nullptr);
    }

    return it->second;
  }

  /**
   * @brief 移除没有连接的代理
   * 
   * @return std::size_t 移除数量
   */
  std::size_t RemoveNotConnectedProxy() {
    std::size_t removed_count = 0;
    for (auto it = client_proxy_map_.begin(); it != client_proxy_map_.end();
         ++it) {
      if (it->second->isConnected()) {
        it = client_proxy_map_.erase(it);
        removed_count++;
      }
    }
    return removed_count++;
  }
  
  /// 遍历代理回调函数类型
  using ForeachProxyCallbackType =
      std::function<void(const role_uuid_type, const std::shared_ptr<ClientProxy>)>;

  /**
   * @brief 遍历所有代理连接
   * 
   * @param callback 
   */
  void ForeachProxy(const ForeachProxyCallbackType callback) const {
    if (!callback) {
      return;
    }
    for (const auto &it: client_proxy_map_) {
      if (!it.second->isConnected()) {
        continue;
      }
      callback(it.first, it.second);
    }
  }

private:
  /// 所有客户端连接
  std::unordered_map<role_uuid_type, std::shared_ptr<ClientProxy>>
     client_proxy_map_;
};

} // common
} // namespace guild_service